#ifndef TCPSERVER_H
#define TCPSERVER_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <Log.h>

#include <boost/bind.hpp>
#include <boost/smart_ptr.hpp>
#include <boost/asio.hpp>
#include <boost/thread.hpp>

#include <NetworkProtocol.h>
#include <list>

typedef boost::shared_ptr<tcp::socket> socket_ptr;

namespace CSNetworkLib {

	/**
	 *	Klasa obsługująca serwer TCP. Pozwala na utworzenie nowego serwera.
	 *  Klasa typu template, jako template należy użyć klasy która dziedziczy po klasie NetworkProtocol.
	 */
	template<class PROTOCOL>
	class TCPServer
	{
		private:
			boost::asio::io_service io_service;
			tcp::acceptor data_acceptor;
            bool m_break;
		public:
            /**
             * Konstruktor podstawowy, tworzy nowy serwer TCP.
             * @param p port na którym ma być uruchomiony serwer.
             */
			TCPServer(int32_t p) : data_acceptor(io_service, tcp::endpoint(tcp::v4(), p)), m_break(false)
			{
				FUNCTION_TRACK
			}
			/**
			 * Metoda przerywa działanie serwera TCP zamykając socket.
			 */
            inline void Break()
            {
                m_break = true;
                data_acceptor.close();
            }
            /**
             * Metoda czeka okreslony na nowego clienta.
             * @param timeout parametr ignorowany
             * @return false jesli wystapi exception, true jeśli nowy client się połączy.
             */
			inline bool acceptClient(uint32_t timeout = 5000)
			{
				FUNCTION_TRACK
                if (m_break) return false;
				DBUG("Awaiting for new connection");
                try{
                    socket_ptr sock(new tcp::socket(io_service));
                    data_acceptor.accept(*sock);
                    boost::asio::ip::tcp::no_delay option(true);
                    sock->set_option(option);
                    boost::asio::socket_base::keep_alive option2(true);
                    sock->set_option(option2);
                    INFO("New client connected from: %s", sock->remote_endpoint().address().to_string().c_str());
                    new PROTOCOL(sock);
                    return true;
                } catch(const std::exception &ex)
                {
                    ERR("Exception: %s", ex.what());
                } catch(...)
                {
                    ERR("Unknown exception");
                }
                return false;
			}
	};
};

#endif /*TCPSERVER_H*/

